#include <iostream>
#include <sys/types.h>          
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <thread>
#include <mutex>
#include "log.hpp"
#include "redirTerm.hpp"
using namespace std;

Log log;
mutex coutMutex;
enum {
    SOCKET_ERR,
};

void Usage(const char* string)
{
    cout << "\n\rUsage: " << string << " serverIp serverPort\n\n";  
}

int main(int argc, char* argv[])
{
    if(argc != 3) {
        Usage(argv[0]);
    }
    // 创建套接字
    int socketFd = socket(AF_INET, SOCK_DGRAM, 0);
    if(socketFd == -1) {
        // 创建失败
        log(FATAL, "创建套接字失败, fd: %d, 原因: %s\n", socketFd, strerror(errno));
        exit(SOCKET_ERR);
    }
    // 输入服务端的ip和端口号
    string serverIp = argv[1];
    uint16_t serverPort = stoi(argv[2]);
    // 构建服务器信息
    sockaddr_in server;
    memset(&server, 0, sizeof(server));
    server.sin_family = AF_INET;
    server.sin_port = htons(serverPort);
    server.sin_addr.s_addr = inet_addr(serverIp.c_str());
    socklen_t len = sizeof(server);
    string message;
    // 改成多线程，一个读取，一个发送。在UDP中，一个socket可以同时进行读写操作。
    thread t1([&] {
        while(true) {
            // 发送数据
            cout << "@Please enter: ";
            getline(cin, message);
            sendto(socketFd, message.c_str(), message.size(), 0, (sockaddr*)&server, len); 
        }
    });
    thread t2([&] {
        while(true) {
            openTerm();     // 重定向终端，现在使用标准错误输出就是像另一个终端打印
            // 拿到服务端处理后的数据
            string buffer(1024, 0);
            sockaddr_in tmpServer;  
            socklen_t tmpLen;
            if(recvfrom(socketFd, (char*)buffer.c_str(), buffer.size(), 0, (sockaddr*)&tmpServer, &tmpLen) > 0) {
                lock_guard<mutex> lock(coutMutex);
                cerr << "Received:" << buffer << endl;
            }
        }
    });
    t1.join();
    t2.join();
    return 0;
}